from maix import image, camera, display, app, time
import numpy as np 
import cv2

kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
cam = camera.Camera(320,240) #初始化相机
disp = display.Display() #初始化显示屏

last_cv2_img = None

kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))

#flag:调试参数 0:调试 1:实际效果  mode:轮廓检测模式  0:检测外框 1:检测所有  number:检测轮廓的边长数量(0为检查所有边框)
def get_contour(mode=0, number=0, flag=0 ):
    points = []
    if mode == 0:
        find_mode = cv2.RETR_EXTERNAL
    else:
        find_mode = cv2.RETR_TREE

    cv_img_raw = image.image2cv(img) # 转cv
    cv_img = cv2.cvtColor(cv_img_raw, cv2.COLOR_BGR2GRAY) # 转灰度
    #cv_img = cv2.blur(cv_img,(4,4))
    #cv_img = cv2.bilateralFilter(cv_img,9,10,10)     # 双边滤波
    #cv_img = cv2.morphologyEx(cv_img,cv2.MORPH_CLOSE,kernel) # 闭运算
    cv_img = cv2.Canny(cv_img, 200, 300) # 边缘检测
    #cv_img = cv2.morphologyEx(cv_img, cv2.MORPH_CLOSE, np.ones((7,7), np.uint8))  # 闭合大裂缝
    #cv_img = cv2.dilate(cv_img, np.ones((5,5), np.uint8), iterations=1)          # 加粗边缘
    if flag:
        img_show = image.cv2image(cv_img)
        disp.show(img_show)
        print(111)
        return img_show, points  # 调试模式直接返回
    else:
        contours, hierarchy = cv2.findContours(cv_img, find_mode, cv2.CHAIN_APPROX_SIMPLE) # 找轮廓

        # 修复：正确解析层级结构
        if hierarchy is not None:
            hierarchy = hierarchy[0]  # 取出实际层级数组


        # 只处理有效轮廓（面积>=1000）
        valid_contours = []
        for contour in contours:
            area = cv2.contourArea(contour)
            if area < 1000:  # 过滤很小的轮廓
                continue
            valid_contours.append(contour)
        
        if not valid_contours:
            # 没有有效轮廓，直接返回
            return image.cv2image(cv_img_raw), points
            
        # 按面积排序并保留最大和最小
        areas = [(i, cv2.contourArea(contour)) for i, contour in enumerate(valid_contours)]
        sorted_areas = sorted(areas, key=lambda x: x[1])
        min_contour = valid_contours[sorted_areas[0][0]]  # 最小面积
        max_contour = valid_contours[sorted_areas[-1][0]]  # 最大面积
        # 获取最大和最小面积的轮廓索引
        min_idx = sorted_areas[0][0]
        max_idx = sorted_areas[-1][0]
        selected_contours = [min_contour, max_contour]


        for i, contour in enumerate(selected_contours):
            # 使用有效轮廓列表中的索引
            # 注意：现在i对应的是selected_contours的索引，而不是原contours
            epsilon = 0.02 * cv2.arcLength(contour, True)
            approx = cv2.approxPolyDP(contour, epsilon, True)
            
            if number != 0:
                # 跳过不符合顶点数量的轮廓
                if len(approx) != number:
                    continue

            if mode == 0:
                cv2.drawContours(cv_img_raw, [approx], 0, (0, 255, 0), 2)
                quad_points = []
                for point in approx:
                    x, y = point.ravel()
                    quad_points.append([x, y])
                    cv2.circle(cv_img_raw, (x, y), 5, (255, 0, 0), 1)
                points = quad_points  # 仅保留最后一个轮廓点
            else:
                # 根据层级或面积判断内外轮廓
                if i == max_idx:  # 最大面积默认为外轮廓
                    quad_points = []
                    for point in approx:
                        x, y = point.ravel()
                        quad_points.append([x, y])
                    points.append(quad_points)
                else:  # 最小面积默认为内轮廓
                    quad_points = []
                    for point in approx:
                        x, y = point.ravel()
                        quad_points.append([x, y])
                    points.append(quad_points)
                
                cv2.drawContours(cv_img_raw, [approx], 0, (0, 255, 0), 2)
                for point in approx:
                    x, y = point.ravel()
                    cv2.circle(cv_img_raw, (x, y), 5, (255, 0, 0), 1)

        img_show = image.cv2image(cv_img_raw)
        return img_show, points

def get_sport():
    global last_cv2_img
    cv2_raw = image.image2cv(img)

    cv2_gray_img = cv2.cvtColor(cv2_raw , cv2.COLOR_BGR2GRAY) # 转灰度
    if last_cv2_img is None:
        last_cv2_img = cv2_gray_img.copy()

    #计算差值
    cv2_diff = cv2.absdiff(cv2_gray_img,last_cv2_img)

    #二值化
    _ , cv2_binary = cv2.threshold(cv2_diff , 25 ,255 , cv2.THRESH_BINARY)

    #膨胀处理
    cv2_binary = cv2.dilate(cv2_binary , kernel , iterations = 2)

    # 找轮廓
    contours , _ = cv2.findContours(cv2_binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    for contour in contours:
        #计算面积
        area = cv2.contourArea(contour)

        if area < 1000:
            print("已经找到物体")
            #用质心做运动物体的中心坐标
            M = cv2.moments(contour)
            point_x = int(M["m10"]/M["m00"])
            point_y = int(M["m01"]/M["m00"])
            img.draw_cross(point_x , point_y , image.COLOR_BLUE , 5,2)
            #获得轮廓的外接矩形
            x , y ,w ,h = cv2.boundingRect(contour)
            #获得该区域的直方图统计数据
            hist = img.get_histogram(thresholds= [[0,100,-128,127,-128,127]] , roi = [x,y,w,h])
            value = hist.get_statistics()

    last_cv2_img = cv2_gray_img.copy()


while not app.need_exit():
    img = cam.read()
    #img , _ = get_contour()
    get_sport()
    disp.show(img)
    print(time.fps())